home *** CD-ROM | disk | FTP | other *** search
/ Delphi Developer's Kit 1996 / Delphi Developer's Kit 1996.iso / power / coolcalc / infix.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-12-22  |  46.5 KB  |  1,410 lines

  1. Unit Infix;
  2.  
  3. { ------------------------------------------------------------------------
  4.   INFIX.PAS
  5.   ------------------------------------------------------------------------
  6.  
  7.     This unit uses recursive descent to evaluate expressions
  8.     written in infix notation.  The operations addition (+),
  9.     subtraction (-), multiplication (*), and division (/) are supported,
  10.     as are the functions ABS, ARCTAN, COS, EXP, LN, SQR, and SQRT.
  11.     PI returns the value for pi.  Results exceeding 1.0E37 are reported
  12.     as overflows.  Results less than 1.0E-37 are set to zero.
  13.  
  14.          Written by:
  15.  
  16.          James L. Dean
  17.          406 40th Street
  18.          New Orleans, LA 70124
  19.          February 25, 1985
  20.  
  21.          Modified by:
  22.  
  23.          David J. Firth
  24.          5665-A2 Parkville St.
  25.          Columbus, OH 43229
  26.          December 26, 1991
  27.  
  28.      This code was originally written as a stand-alone program using
  29.      standard Pascal.  In that form the program wasn't very useful.
  30.      I have taken the code and reorganized it for use with Turbo Pascal
  31.      versions 5.x or 6.0.  In addition, I have reworked it to support
  32.      variables by adding a preprocessor.  The variables are preceded and
  33.      followed by a @ symbol, are case sensitive, and must be less than
  34.      20 characters long (including the 2 @s). For example, the
  35.      following would all be valid variables:
  36.  
  37.      @VARIABLE1@      @Pressure3@      @AngleOfAttack@
  38.  
  39.      Variable identifiers are passed around as strings.
  40.  
  41.      Calculation results may either be stored in variables or returned
  42.      raw to the caller.  Raw calculations may not contain variables,
  43.      since the raw procedure calls are sent directly to the original
  44.      code.
  45.  
  46.      As a final note, the original code is virtually unreadable due
  47.      to the original author's lack of any comments.  I have attempted
  48.      to provide a front end to this code that is useful and understandable.
  49.  
  50.      Your comments are welcome (and desired!). My E-Mail addresses
  51.      are:
  52.  
  53.      GEnie:     D.FIRTH
  54.      CIS:       76467,1734
  55. }
  56.  
  57. Interface
  58.  
  59. type
  60.  
  61.   Str20 = string[20];                 {store variable IDs this way to conserve}
  62.  
  63.   VariablePtr = ^VariableType;        {for dynamic allocation of records }
  64.  
  65.   VariableType = record
  66.     ID    : Str20;                    {the id of the variable, with @s   }
  67.     Value : real;                     {the current value of the variable }
  68.     Next  : VariablePtr;              {hook to next record in linked list}
  69.   end; {VariableType}
  70.  
  71. var
  72.  
  73.   HPtr,                               {head of variable list       }
  74.   TPtr,                               {tail of variable list       }
  75.   SPtr  : VariablePtr;                {used to search variable list}
  76.  
  77.   CalcError : integer;                {the position of the error   }
  78.  
  79. procedure StoreVariable(VariableID:str20;MyValue:real);
  80. procedure ReadVariable(VariableID:str20;var MyValue:real;var MyError:boolean);
  81. procedure DestroyList;
  82.  
  83. procedure RawCalculate(MyFormula:string;var MyResult:real;var MyError:byte);
  84. procedure Calculate(MyFormula:string;var MyResult:real;var MyError:byte);
  85. procedure CalcAndStore(MyFormula:string;StoreID:str20;var MyError:byte);
  86.  
  87. Implementation
  88.  
  89. { ------------------------------------------------------------------------ }
  90.  
  91.   TYPE
  92.  
  93.     argument_record_ptr = ^argument_record;
  94.  
  95.     argument_record = RECORD
  96.                         value : REAL;
  97.                         next_ptr : argument_record_ptr
  98.                       END;
  99.  
  100.     string_1 = STRING[1];
  101.  
  102.     string_255 = STRING[255];
  103.  
  104.   VAR
  105.  
  106.     error_detected              : BOOLEAN;
  107.     error_msg                   : string_255;
  108.     expression                  : string_255; 
  109.     expression_index            : INTEGER;
  110.     expression_length           : INTEGER;
  111.     xresult                     : REAL;    { 8/11/95 dfn: result -> xresult }
  112.  
  113. { ------------------------------------------------------------------------ }
  114.  
  115.   PROCEDURE set_error(msg : string_255);
  116.     BEGIN
  117.       error_detected:=TRUE;
  118.       error_msg
  119.        :='Error:  '+msg+'.'
  120.     END;
  121.  
  122. { ------------------------------------------------------------------------ }
  123.  
  124.   PROCEDURE eat_leading_spaces;
  125.     VAR
  126.       non_blank_found           : BOOLEAN;
  127.     BEGIN
  128.       non_blank_found:=FALSE;
  129.       WHILE((expression_index <= expression_length)
  130.       AND   (NOT non_blank_found)) DO
  131.         IF expression[expression_index] = ' ' THEN
  132.           expression_index:=expression_index+1
  133.         ELSE
  134.           non_blank_found:=TRUE
  135.     END;
  136.  
  137. { ------------------------------------------------------------------------ }
  138.  
  139.   FUNCTION unsigned_integer : REAL;
  140.     VAR
  141.       non_digit_found           : BOOLEAN;
  142.       overflow                  : BOOLEAN;
  143.       xresult                   : REAL;    { 8/11/95 dfn: result -> xresult }
  144.       tem_char                  : CHAR;
  145.       tem_real                  : REAL;
  146.     BEGIN
  147.       non_digit_found:=FALSE;
  148.       xresult:=0.0;
  149.       overflow:=FALSE;
  150.       REPEAT
  151.         tem_char:=expression[expression_index];
  152.         IF ((tem_char >= '0') AND (tem_char <= '9')) THEN
  153.           BEGIN
  154.             tem_real:=ORD(tem_char)-ORD('0');
  155.             IF xresult > 1.0E36 THEN
  156.               overflow:=TRUE
  157.             ELSE
  158.               BEGIN
  159.                 xresult:=10.0*xresult+tem_real;
  160.                 expression_index:=expression_index+1;
  161.                 IF expression_index > expression_length THEN
  162.                   non_digit_found:=TRUE
  163.               END
  164.           END
  165.         ELSE
  166.           non_digit_found:=TRUE
  167.       UNTIL ((non_digit_found) OR (overflow));
  168.       IF overflow THEN
  169.         set_error('constant is too big');
  170.       unsigned_integer:=xresult
  171.     END;
  172.  
  173. { ------------------------------------------------------------------------ }
  174.  
  175.   FUNCTION unsigned_number : REAL;
  176.     VAR
  177.       exponent_value            : REAL;
  178.       exponent_sign             : CHAR;
  179.       factor                    : REAL;
  180.       non_digit_found           : BOOLEAN;
  181.       xresult                   : REAL; { 8/11/95 dfn: result -> xresult }
  182.       tem_char                  : CHAR;
  183.       tem_real_1                : REAL;
  184.       tem_real_2                : REAL;
  185.     BEGIN
  186.       xresult:=unsigned_integer;
  187.       IF (NOT error_detected) THEN
  188.         BEGIN
  189.           IF expression_index <= expression_length THEN
  190.             BEGIN
  191.               tem_char:=expression[expression_index];
  192.               IF tem_char = '.' THEN
  193.                 BEGIN
  194.                   tem_real_1:=xresult;
  195.                   expression_index:=expression_index+1;
  196.                   IF expression_index > expression_length THEN
  197.                     set_error(
  198.             'end of expression encountered where decimal part expected')
  199.                   ELSE
  200.                     BEGIN
  201.                       tem_char:=expression[expression_index];
  202.                       IF ((tem_char >= '0') AND (tem_char <= '9')) THEN
  203.                         BEGIN
  204.                           factor:=1.0;
  205.                           non_digit_found:=FALSE;
  206.                           WHILE (NOT non_digit_found) DO
  207.                             BEGIN
  208.                               factor:=factor/10.0;
  209.                               tem_real_2:=ORD(tem_char)-ORD('0');
  210.                               tem_real_1:=tem_real_1+factor*tem_real_2;
  211.                               expression_index:=expression_index+1;
  212.                               IF expression_index > expression_length THEN
  213.                                non_digit_found:=TRUE
  214.                               ELSE
  215.                                 BEGIN
  216.                                   tem_char
  217.                                    :=expression[expression_index];
  218.                                   IF ((tem_char < '0')
  219.                                   OR  (tem_char > '9')) THEN
  220.                                     non_digit_found:=TRUE
  221.                                 END
  222.                             END;
  223.                           xresult:=tem_real_1
  224.                         END
  225.                       ELSE
  226.                         set_error(
  227.                          'decimal part of real number is missing')
  228.                     END
  229.                 END;
  230.               IF (NOT error_detected) THEN
  231.                 BEGIN
  232.                   IF expression_index <= expression_length THEN
  233.                     BEGIN
  234.                       IF ((tem_char = 'e') OR (tem_char = 'E')) THEN
  235.                         BEGIN
  236.                           expression_index:=expression_index+1;
  237.                           IF expression_index > expression_length THEN
  238.                             set_error(
  239.                'end of expression encountered where exponent expected')
  240.                          ELSE
  241.                             BEGIN
  242.                               tem_char
  243.                                :=expression[expression_index];
  244.                               IF ((tem_char = '+')
  245.                               OR  (tem_char = '-')) THEN
  246.                                 BEGIN
  247.                                   exponent_sign:=tem_char;
  248.                                   expression_index:=expression_index+1
  249.                                 END
  250.                               ELSE
  251.                                 exponent_sign:=' ';
  252.                               IF expression_index > expression_length
  253.                                THEN
  254.                                 set_error(
  255.      'end of expression encountered where exponent magnitude expected')
  256.                               ELSE
  257.                                 BEGIN
  258.                                   tem_char:=expression[expression_index];
  259.                                  IF ((tem_char >= '0')
  260.                                   AND (tem_char <= '9')) THEN
  261.                                     BEGIN
  262.                                       exponent_value
  263.                                        :=unsigned_integer;
  264.                                       IF (NOT error_detected) THEN
  265.                                         BEGIN
  266.                                           IF exponent_value > 37.0 THEN
  267.                                             set_error(
  268.                                    'magnitude of exponent is too large')
  269.                                           ELSE
  270.                                             BEGIN
  271.                                               tem_real_1:=1.0;
  272.                                               WHILE (exponent_value > 0.0) DO
  273.                                                 BEGIN
  274.                                                   exponent_value
  275.                                                    :=exponent_value-1.0;
  276.                                                   tem_real_1:=10.0*tem_real_1
  277.                                                 END;
  278.                                               IF exponent_sign = '-' THEN
  279.                                                tem_real_1
  280.                                                 :=1.0/tem_real_1;
  281.                                               IF xresult <> 0.0 THEN
  282.                                                 BEGIN
  283.                                                   tem_real_2
  284.                                                    :=(LN(tem_real_1)
  285.                                                    +LN(ABS(xresult)))
  286.                                                    /LN(10.0);
  287.                                                   IF tem_real_2 < -37.0 THEN
  288.                                                     xresult:=0.0
  289.                                                   ELSE
  290.                                                     IF tem_real_2 > 37.0 THEN
  291.                                                       set_error(
  292.                                                        'constant is too big')
  293.                                                     ELSE
  294.                                                       xresult:=xresult*tem_real_1
  295.                                                 END
  296.                                             END
  297.                                         END
  298.                                     END
  299.                                   ELSE
  300.                                     set_error(
  301.                                      'nonnumeric exponent encountered')
  302.                                 END
  303.                             END
  304.                         END
  305.                     END
  306.                 END
  307.             END
  308.         END;
  309.       unsigned_number:=xresult
  310.     END;
  311.  
  312. { ------------------------------------------------------------------------ }
  313.  
  314.   FUNCTION pop_argument(VAR argument_stack_head : argument_record_ptr) : REAL;
  315.     VAR
  316.       argument_stack_ptr        : argument_record_ptr;
  317.       xresult                   : REAL;  { 8/11/95 dfn: result -> xresult }
  318.     BEGIN
  319.       xresult:=argument_stack_head^.value;
  320.       argument_stack_ptr:=argument_stack_head^.next_ptr;
  321.       DISPOSE(argument_stack_head);
  322.       argument_stack_head:=argument_stack_ptr;
  323.       pop_argument:=xresult
  324.     END;
  325.  
  326. { ------------------------------------------------------------------------ }
  327.  
  328.   FUNCTION abs_function(VAR argument_stack_head : argument_record_ptr;
  329.    VAR function_name : string_255) : REAL;
  330.     VAR
  331.       argument                  : REAL;
  332.       xresult                   : REAL;   { 8/11/95 dfn: result -> xresult }
  333.     BEGIN
  334.       xresult:=0.0;
  335.       IF argument_stack_head = NIL THEN
  336.         set_error('argument to "'+function_name+'" is missing')
  337.       ELSE
  338.         BEGIN
  339.           argument:=pop_argument(argument_stack_head);
  340.           IF argument_stack_head = NIL THEN
  341.             IF argument >= 0.0 THEN
  342.               xresult:=argument
  343.             ELSE
  344.               xresult:=-argument
  345.           ELSE
  346.             set_error(
  347.              'extraneous argument supplied to function "'+
  348.              function_name+'"')
  349.         END;
  350.       abs_function:=xresult
  351.     END;
  352.  
  353. { ------------------------------------------------------------------------ }
  354.  
  355.   FUNCTION arctan_function(VAR argument_stack_head : argument_record_ptr;
  356.    VAR function_name : string_255) : REAL;
  357.     VAR
  358.       argument                  : REAL;
  359.       xresult                   : REAL; { 8/11/95 dfn: result -> xresult }
  360.     BEGIN
  361.       xresult:=0.0;
  362.       IF argument_stack_head = NIL THEN
  363.        set_error(
  364.         'argument to "'+function_name+'" is missing')
  365.       ELSE
  366.         BEGIN
  367.           argument:=pop_argument(argument_stack_head);
  368.           IF argument_stack_head = NIL THEN
  369.             xresult:=ARCTAN(argument)
  370.           ELSE
  371.             set_error(
  372.              'extraneous argument supplied to function "'+
  373.              function_name+'"')
  374.         END;
  375.       arctan_function:=xresult
  376.     END;
  377.  
  378. { ------------------------------------------------------------------------ }
  379.  
  380.   FUNCTION cos_function(VAR argument_stack_head : argument_record_ptr;
  381.    VAR function_name : string_255) : REAL;
  382.     VAR
  383.       argument                  : REAL;
  384.       xresult                   : REAL;  { 8/11/95 dfn: result -> xresult }
  385.     BEGIN
  386.       xresult:=0.0;
  387.       IF argument_stack_head = NIL THEN
  388.         set_error('argument to "'+function_name+'" is missing')
  389.       ELSE
  390.         BEGIN
  391.           argument:=pop_argument(argument_stack_head);
  392.           IF argument_stack_head = NIL THEN
  393.             xresult:=COS(argument)
  394.           ELSE
  395.             set_error(
  396.              'extraneous argument supplied to function "'+
  397.              function_name+'"')
  398.         END;
  399.       cos_function:=xresult
  400.     END;
  401.  
  402. { ------------------------------------------------------------------------ }
  403.  
  404.   FUNCTION exp_function(VAR argument_stack_head : argument_record_ptr;
  405.    VAR function_name : string_255) : REAL;
  406.     VAR
  407.       argument                  : REAL;
  408.       xresult                   : REAL; { 8/11/95 dfn: result -> xresult }
  409.       tem_real                  : REAL;
  410.     BEGIN
  411.       xresult:=0.0;
  412.       IF argument_stack_head = NIL THEN
  413.         set_error('argument to "'+function_name+'" is missing')
  414.       ELSE
  415.         BEGIN
  416.           argument:=pop_argument(argument_stack_head);
  417.           IF argument_stack_head = NIL THEN
  418.             BEGIN
  419.               tem_real:=argument/LN(10.0);
  420.               IF tem_real < -37.0 THEN
  421.                 xresult:=0.0
  422.               ELSE
  423.                 IF tem_real > 37.0 THEN
  424.                   set_error(
  425.                    'overflow detected while calculating "'+
  426.                    function_name+'"')
  427.                 ELSE
  428.                   xresult:=EXP(argument)
  429.             END
  430.           ELSE
  431.             set_error(
  432.              'extraneous argument supplied to function "'+
  433.              function_name+'"')
  434.         END;
  435.       exp_function:=xresult
  436.     END;
  437.  
  438. { ------------------------------------------------------------------------ }
  439.  
  440.   FUNCTION ln_function(VAR argument_stack_head : argument_record_ptr;
  441.    VAR function_name : string_255) : REAL;
  442.     VAR
  443.       argument                  : REAL;
  444.       xresult                   : REAL; { 8/11/95 dfn: result -> xresult }
  445.     BEGIN
  446.       xresult:=0.0;
  447.       IF argument_stack_head = NIL THEN
  448.         set_error(
  449.          'argument to "'+function_name+'" is missing')
  450.       ELSE
  451.         BEGIN
  452.           argument:=pop_argument(argument_stack_head);
  453.           IF argument_stack_head = NIL THEN
  454.             IF argument <= 0.0 THEN
  455.               set_error(
  456.                'argument to "'+function_name+
  457.                '" is other than positive')
  458.             ELSE
  459.               xresult:=LN(argument)
  460.           ELSE
  461.             set_error(
  462.              'extraneous argument supplied to function "'+
  463.              function_name+'"')
  464.         END;
  465.       ln_function:=xresult
  466.     END;
  467.  
  468. { ------------------------------------------------------------------------ }
  469.  
  470.   FUNCTION pi_function(VAR argument_stack_head : argument_record_ptr;
  471.    VAR function_name : string_255) : REAL;
  472.     VAR
  473.       argument                  : REAL;
  474.       xresult                   : REAL;    { 8/11/95 dfn: result -> xresult }
  475.     BEGIN
  476.       xresult:=0.0;
  477.       IF argument_stack_head = NIL THEN
  478.         xresult:=4.0*ARCTAN(1.0)
  479.       ELSE
  480.         set_error(
  481.          'extraneous argument supplied to function "'+
  482.          function_name+'"');
  483.       pi_function:=xresult
  484.     END;
  485.  
  486. { ------------------------------------------------------------------------ }
  487.  
  488.   FUNCTION sin_function(VAR argument_stack_head : argument_record_ptr;
  489.    VAR function_name : string_255) : REAL;
  490.     VAR
  491.       argument                  : REAL;
  492.       xresult                   : REAL;    { 8/11/95 dfn: result -> xresult }
  493.     BEGIN
  494.       xresult:=0.0;
  495.       IF argument_stack_head = NIL THEN
  496.         set_error(
  497.          'argument to "'+function_name+'" is missing')
  498.       ELSE
  499.         BEGIN
  500.           argument:=pop_argument(argument_stack_head);
  501.           IF argument_stack_head = NIL THEN
  502.             xresult:=SIN(argument)
  503.           ELSE
  504.             set_error(
  505.              'extraneous argument supplied to function "'+
  506.              function_name+'"')
  507.         END;
  508.       sin_function:=xresult
  509.     END;
  510.  
  511. { ------------------------------------------------------------------------ }
  512.  
  513.   FUNCTION sqr_function(VAR argument_stack_head : argument_record_ptr;
  514.    VAR function_name : string_255) : REAL;
  515.     VAR
  516.       argument                  : REAL;
  517.       xresult                   : REAL;    { 8/11/95 dfn: result -> xresult }
  518.       tem_real                  : REAL;
  519.     BEGIN
  520.       xresult:=0.0;
  521.       IF argument_stack_head = NIL THEN
  522.         set_error(
  523.          'argument to "'+function_name+'" is missing')
  524.       ELSE
  525.         BEGIN
  526.           argument:=pop_argument(argument_stack_head);
  527.           IF argument_stack_head = NIL THEN
  528.             IF argument = 0.0 THEN
  529.               xresult:=0.0
  530.             ELSE
  531.               BEGIN
  532.                 tem_real:=2.0*LN(ABS(argument))/LN(10.0);
  533.                 IF tem_real < -37.0 THEN
  534.                   xresult:=0.0
  535.                 ELSE
  536.                   IF tem_real > 37.0 THEN
  537.                     set_error(
  538.                      'overflow detected during calculation of "'+
  539.                      function_name+'"')
  540.                   ELSE
  541.                     xresult:=argument*argument
  542.               END
  543.           ELSE
  544.             set_error(
  545.              'extraneous argument supplied to function "'+
  546.              function_name+'"')
  547.         END;
  548.       sqr_function:=xresult
  549.     END;
  550.  
  551. { ------------------------------------------------------------------------ }
  552.  
  553.   FUNCTION sqrt_function(VAR argument_stack_head : argument_record_ptr;
  554.    VAR function_name : string_255) : REAL;
  555.     VAR
  556.       argument                  : REAL;
  557.       xresult                   : REAL;  { 8/11/95 dfn: result -> xresult }
  558.     BEGIN
  559.       xresult:=0.0;
  560.       IF argument_stack_head = NIL THEN
  561.         set_error(
  562.          'argument to "'+function_name+'" is missing')
  563.       ELSE
  564.         BEGIN
  565.           argument:=pop_argument(argument_stack_head);
  566.           IF argument_stack_head = NIL THEN
  567.             IF argument < 0.0 THEN
  568.               set_error(
  569.                'argument to "'+function_name+
  570.                '" is negative')
  571.             ELSE
  572.               xresult:=SQRT(argument)
  573.           ELSE
  574.             set_error(
  575.              'extraneous argument supplied to function "'+
  576.              function_name+'"')
  577.         END;
  578.       sqrt_function:=xresult
  579.     END;
  580.  
  581. { ------------------------------------------------------------------------ }
  582.  
  583.   FUNCTION simple_expression : REAL; FORWARD;
  584.  
  585. { ------------------------------------------------------------------------ }
  586.  
  587.   FUNCTION funct : REAL;
  588.     VAR
  589.       argument                  : REAL;
  590.       argument_stack_head       : argument_record_ptr;
  591.       argument_stack_ptr        : argument_record_ptr;
  592.       arguments_okay            : BOOLEAN;
  593.       function_name             : string_255;
  594.       non_alphanumeric_found    : BOOLEAN;
  595.       xresult                   : REAL;    { 8/11/95 dfn: result -> xresult }
  596.       right_parenthesis_found   : BOOLEAN;
  597.       tem_char                  : CHAR;
  598.     BEGIN    
  599.       xresult:=0.0;
  600.       non_alphanumeric_found:=FALSE;
  601.       function_name:='';
  602.       WHILE((expression_index <= expression_length)
  603.       AND   (NOT non_alphanumeric_found)) DO
  604.         BEGIN
  605.           tem_char:=expression[expression_index];
  606.           tem_char:=UPCASE(tem_char);
  607.           IF ((tem_char >= 'A') AND (tem_char <= 'Z')) THEN
  608.             BEGIN
  609.               function_name:=function_name+tem_char;
  610.               expression_index:=expression_index+1
  611.             END
  612.           ELSE
  613.             non_alphanumeric_found:=TRUE
  614.         END;
  615.       argument_stack_head:=NIL;
  616.       arguments_okay:=TRUE;
  617.       eat_leading_spaces;
  618.       IF expression_index <= expression_length THEN
  619.         BEGIN
  620.           tem_char:=expression[expression_index];
  621.           IF tem_char = '(' THEN
  622.             BEGIN
  623.               expression_index:=expression_index+1;
  624.               right_parenthesis_found:=FALSE;
  625.               WHILE ((NOT right_parenthesis_found)
  626.               AND    (arguments_okay)
  627.               AND    (expression_index <= expression_length)) DO
  628.                 BEGIN
  629.                   argument:=simple_expression;
  630.                   IF error_detected THEN
  631.                     arguments_okay:=FALSE
  632.                   ELSE
  633.                     BEGIN
  634.                       IF argument_stack_head = NIL THEN
  635.                         BEGIN
  636.                           NEW(argument_stack_head);
  637.                           argument_stack_head^.value:=argument;
  638.                           argument_stack_head^.next_ptr:=NIL
  639.                         END
  640.                       ELSE
  641.                         BEGIN
  642.                           NEW(argument_stack_ptr);
  643.                           argument_stack_ptr^.value:=argument;
  644.                           argument_stack_ptr^.next_ptr
  645.                            :=argument_stack_head;
  646.                           argument_stack_head:=argument_stack_ptr
  647.                         END;
  648.                       eat_leading_spaces;
  649.                       IF expression_index <= expression_length THEN
  650.                         BEGIN
  651.                           tem_char:=expression[expression_index];
  652.                           IF tem_char = ')' THEN
  653.                             BEGIN
  654.                               right_parenthesis_found:=TRUE;
  655.                               expression_index:=expression_index+1
  656.                             END
  657.                           ELSE
  658.                             IF tem_char = ',' THEN
  659.                               expression_index:=expression_index+1
  660.                             ELSE
  661.                               BEGIN
  662.                                 arguments_okay:=FALSE;
  663.                                 set_error(
  664.                             'comma missing from function arguments')
  665.                               END
  666.                         END
  667.                     END
  668.                 END;
  669.               IF arguments_okay THEN
  670.                 BEGIN
  671.                   IF (NOT right_parenthesis_found) THEN
  672.                     BEGIN
  673.                       arguments_okay:=FALSE;
  674.                       set_error(
  675.                    '")" to terminate function arguments is missing')
  676.                     END
  677.                 END
  678.             END
  679.         END;
  680.       IF arguments_okay THEN
  681.         BEGIN
  682.           IF function_name = 'ABS' THEN
  683.             xresult
  684.              :=abs_function(argument_stack_head,function_name) 
  685.           ELSE
  686.             IF function_name = 'ARCTAN' THEN
  687.               xresult
  688.                :=arctan_function(argument_stack_head,function_name)
  689.             ELSE
  690.               IF function_name = 'COS' THEN
  691.                 xresult
  692.                  :=cos_function(argument_stack_head,function_name)
  693.               ELSE
  694.                 IF function_name = 'EXP' THEN
  695.                   xresult
  696.                    :=exp_function(argument_stack_head,function_name)
  697.                 ELSE
  698.                   IF function_name = 'LN' THEN
  699.                     xresult
  700.                      :=ln_function(argument_stack_head,function_name)
  701.                   ELSE
  702.                     IF function_name = 'PI' THEN
  703.                       xresult
  704.                        :=pi_function(argument_stack_head,function_name)
  705.                     ELSE
  706.                       IF function_name = 'SIN' THEN
  707.                         xresult
  708.                          :=sin_function(argument_stack_head,function_name)
  709.                       ELSE
  710.                         IF function_name = 'SQR' THEN
  711.                           xresult
  712.                            :=sqr_function(argument_stack_head,function_name)
  713.                         ELSE
  714.                           IF function_name = 'SQRT' THEN
  715.                             xresult
  716.                              :=sqrt_function(argument_stack_head,function_name)
  717.                           ELSE
  718.                             set_error('the function "'+
  719.                              function_name+'" is unrecognized')
  720.         END;
  721.       WHILE (argument_stack_head <> NIL) DO
  722.         BEGIN
  723.           argument_stack_ptr:=argument_stack_head^.next_ptr;
  724.           DISPOSE(argument_stack_head);
  725.           argument_stack_head:=argument_stack_ptr
  726.         END;
  727.       funct:=result
  728.     END;
  729.  
  730. { ------------------------------------------------------------------------ }
  731.  
  732.   FUNCTION factor : REAL;
  733.     VAR
  734.       xresult                   : REAL;    { 8/11/95 dfn: result -> xresult }
  735.       tem_char                  : CHAR;
  736.     BEGIN
  737.       xresult:=0.0;
  738.       eat_leading_spaces;
  739.       IF expression_index > expression_length THEN
  740.         set_error(
  741.          'end of expression encountered where factor expected')
  742.       ELSE
  743.         BEGIN
  744.           tem_char:=expression[expression_index];
  745.           BEGIN
  746.             IF tem_char = '(' THEN
  747.               BEGIN
  748.                 expression_index:=expression_index+1;
  749.                 xresult:=simple_expression;
  750.                 IF (NOT error_detected) THEN
  751.                   BEGIN
  752.                     eat_leading_spaces;
  753.                     IF expression_index > expression_length THEN
  754.                       set_error(
  755.                        'end of expression encountered '+
  756.                        'where ")" was expected')
  757.                     ELSE
  758.                       IF expression[expression_index] = ')' THEN
  759.                         expression_index:=expression_index+1
  760.                       ELSE
  761.                         set_error('expression not followed by ")"')
  762.                   END
  763.               END
  764.             ELSE
  765.               IF ((tem_char >= '0') AND (tem_char <= '9')) THEN
  766.                 xresult:=unsigned_number
  767.               ELSE
  768.                 IF (((tem_char >= 'a') AND (tem_char <= 'z'))
  769.                 OR  ((tem_char >= 'A') AND (tem_char <= 'Z'))) THEN
  770.                   xresult:=funct
  771.                 ELSE
  772.                   set_error(
  773.                    'function, unsigned number, or "(" expected')
  774.           END
  775.         END;
  776.       factor:=xresult
  777.     END;
  778.  
  779. { ------------------------------------------------------------------------ }
  780.  
  781.   FUNCTION quotient_of_factors(VAR left_value,right_value : REAL) : REAL;
  782.     VAR
  783.       xresult                   : REAL; { 8/11/95 dfn: result -> xresult }
  784.       tem_real                  : REAL;
  785.     BEGIN
  786.       xresult:=0.0;
  787.       IF right_value = 0.0 THEN
  788.         set_error('division by zero attempted')
  789.       ELSE
  790.         BEGIN
  791.           IF left_value = 0.0 THEN
  792.             xresult:=0.0
  793.           ELSE
  794.             BEGIN
  795.               tem_real:=(LN(ABS(left_value))-LN(ABS(right_value)))/LN(10.0);
  796.               IF tem_real < -37.0 THEN 
  797.                 xresult:=0.0
  798.               ELSE
  799.                 IF tem_real > 37.0 THEN
  800.                   set_error(
  801.                    'overflow detected during division')
  802.                 ELSE
  803.                   xresult:=left_value/right_value
  804.             END
  805.         END;
  806.       quotient_of_factors:=xresult
  807.     END;
  808.  
  809. { ------------------------------------------------------------------------ }
  810.  
  811.   FUNCTION product_of_factors(VAR left_value,right_value : REAL) : REAL;
  812.     VAR
  813.       xresult                   : REAL; { 8/11/95 dfn: result -> xresult }
  814.       tem_real                  : REAL;
  815.     BEGIN
  816.       xresult:=0.0;
  817.       IF ((left_value <> 0.0) AND (right_value <> 0.0)) THEN
  818.         BEGIN
  819.           tem_real:=(LN(ABS(left_value))+LN(ABS(right_value)))/LN(10.0); 
  820.           IF tem_real < -37.0 THEN
  821.             xresult:=0.0
  822.           ELSE
  823.             IF tem_real > 37.0 THEN
  824.               set_error(
  825.                'overflow detected during multiplication')
  826.             ELSE
  827.               xresult:=left_value*right_value
  828.         END;
  829.       product_of_factors:=xresult
  830.     END;
  831.  
  832. { ------------------------------------------------------------------------ }
  833.  
  834.   FUNCTION factor_operator : string_1;
  835.     VAR
  836.       xresult                   : string_1; { 8/11/95 dfn: result -> xresult }
  837.     BEGIN
  838.       eat_leading_spaces;
  839.       IF expression_index <= expression_length THEN
  840.         BEGIN
  841.           xresult:=expression[expression_index];
  842.           IF ((xresult = '*')
  843.           OR  (xresult = '/')) THEN
  844.             expression_index:=expression_index+1
  845.         END
  846.       ELSE
  847.         xresult:='';
  848.       factor_operator:=xresult
  849.     END;
  850.  
  851. { ------------------------------------------------------------------------ }
  852.  
  853.   FUNCTION term : REAL;
  854.     VAR
  855.       operator                  : string_1;
  856.       operator_found            : BOOLEAN;
  857.       xresult                   : REAL;    { 8/11/95 dfn: result -> xresult }
  858.       right_value               : REAL;
  859.     BEGIN
  860.       xresult:=0;
  861.       eat_leading_spaces;
  862.       IF expression_index > expression_length THEN
  863.         set_error(
  864.          'end of expression encountered where term was expected')
  865.       ELSE
  866.         BEGIN
  867.           xresult:=factor;
  868.           operator_found:=TRUE;
  869.           WHILE((NOT error_detected)
  870.           AND   (operator_found)) DO
  871.             BEGIN
  872.               operator:=factor_operator;
  873.               IF LENGTH(operator) = 0 THEN
  874.                 operator_found:=FALSE
  875.               ELSE
  876.                 IF ((operator <> '*')
  877.                 AND (operator <> '/')) THEN
  878.                   operator_found:=FALSE
  879.                 ELSE
  880.                   BEGIN
  881.                     right_value:=factor;
  882.                     IF (NOT error_detected) THEN
  883.                       BEGIN
  884.                         IF operator = '*' THEN
  885.                             xresult:=product_of_factors(
  886.                              xresult,right_value)
  887.                         ELSE
  888.                             xresult:=quotient_of_factors(
  889.                              xresult,right_value)
  890.                       END
  891.                   END
  892.             END
  893.         END;
  894.       term:=xresult
  895.     END;
  896.  
  897. { ------------------------------------------------------------------------ }
  898.  
  899.   FUNCTION sum_of_terms(VAR left_value,right_value : REAL) : REAL;
  900.     VAR
  901.       xresult                    : REAL;    { 8/11/95 dfn: result -> xresult }
  902.     BEGIN
  903.       xresult:=0.0;
  904.       IF ((left_value > 0.0) AND (right_value > 0.0)) THEN
  905.         IF left_value > (1.0E37 - right_value) THEN
  906.           set_error('overflow detected during addition')
  907.         ELSE
  908.           xresult:=left_value+right_value
  909.       ELSE
  910.         IF ((left_value < 0.0) AND (right_value < 0.0)) THEN
  911.           IF left_value < (-1.0E37 - right_value) THEN
  912.             set_error('overflow detected during addition')
  913.           ELSE
  914.             xresult:=left_value+right_value
  915.         ELSE
  916.           xresult:=left_value+right_value;
  917.       sum_of_terms:=xresult
  918.     END;
  919.  
  920. { ------------------------------------------------------------------------ }
  921.  
  922.   FUNCTION difference_of_terms(VAR left_value,right_value : REAL) : REAL;
  923.     VAR
  924.       xresult                    : REAL;    { 8/11/95 dfn: result -> xresult }
  925.     BEGIN
  926.       IF ((left_value < 0.0) AND (right_value > 0.0)) THEN
  927.         IF left_value < (right_value - 1.0E37) THEN
  928.           set_error('overflow detected during subtraction')
  929.         ELSE
  930.           xresult:=left_value-right_value
  931.       ELSE
  932.         IF ((left_value > 0.0) AND (right_value < 0.0)) THEN
  933.           IF left_value > (right_value + 1.0E37) THEN
  934.             set_error('overflow detected during subtraction')
  935.           ELSE
  936.             xresult:=left_value-right_value
  937.         ELSE
  938.           xresult:=left_value-right_value;
  939.       difference_of_terms:=xresult
  940.     END;
  941.  
  942. { ------------------------------------------------------------------------ }
  943.  
  944.   FUNCTION term_operator : string_1;
  945.     VAR
  946.       xresult                    : string_1;    { 8/11/95 dfn: result -> xresult }
  947.     BEGIN
  948.       eat_leading_spaces;
  949.       IF expression_index <= expression_length THEN
  950.         BEGIN
  951.           xresult:=expression[expression_index];
  952.           IF ((xresult = '+')
  953.           OR  (xresult = '-')) THEN
  954.             expression_index:=expression_index+1
  955.         END
  956.       ELSE
  957.         xresult:='';
  958.       term_operator:=xresult
  959.     END;
  960.  
  961. { ------------------------------------------------------------------------ }
  962.  
  963.   FUNCTION simple_expression;
  964.     VAR
  965.       leading_sign              : CHAR;
  966.       operator                  : string_1;
  967.       operator_found            : BOOLEAN;
  968.       xresult                   : REAL;    { 8/11/95 dfn: result -> xresult }
  969.       right_value               : REAL;
  970.       tem_char                  : CHAR;
  971.     BEGIN
  972.       xresult:=0.0;
  973.       eat_leading_spaces;
  974.       IF expression_index > expression_length THEN
  975.         set_error(
  976.        'end of expression encountered where simple expression expected')
  977.       ELSE
  978.         BEGIN
  979.           leading_sign:=' ';
  980.           tem_char:=expression[expression_index];
  981.           IF ((tem_char = '+') OR (tem_char = '-')) THEN
  982.             BEGIN
  983.               leading_sign:=tem_char;
  984.               expression_index:=expression_index+1
  985.             END;
  986.           xresult:=term;
  987.           IF (NOT error_detected) THEN
  988.             BEGIN
  989.               IF leading_sign <> ' ' THEN
  990.                 BEGIN
  991.                   IF leading_sign = '-' THEN
  992.                     xresult:=-xresult
  993.                 END;
  994.               operator_found:=TRUE;
  995.               WHILE((NOT error_detected)
  996.               AND   (operator_found)) DO
  997.                 BEGIN
  998.                   operator:=term_operator;
  999.                   IF LENGTH(operator) = 0 THEN
  1000.                     operator_found:=FALSE
  1001.                   ELSE
  1002.                     IF ((operator <> '+')
  1003.                     AND (operator <> '-')) THEN
  1004.                       operator_found:=FALSE
  1005.                     ELSE
  1006.                       BEGIN
  1007.                         right_value:=term;
  1008.                         IF (NOT error_detected) THEN
  1009.                           BEGIN
  1010.                             IF operator = '+' THEN
  1011.                               xresult:=sum_of_terms(
  1012.                                xresult,right_value)
  1013.                             ELSE
  1014.                               xresult:=difference_of_terms(
  1015.                                xresult,right_value)
  1016.                           END
  1017.                       END
  1018.                 END
  1019.             END
  1020.         END;
  1021.       simple_expression:=xresult
  1022.     END;
  1023.  
  1024. { ------------------------------------------------------------------------ }
  1025.  
  1026.   PROCEDURE output_value(VAR xresult : REAL);
  1027.  
  1028.   { this procedure used to send text directly to the display.
  1029.     I reworked it to condition the value only and then return. }
  1030.  
  1031.     VAR
  1032.       digits_in_integer_part       : INTEGER;
  1033.       magnitude_of_xresult          : REAL;
  1034.  
  1035.     BEGIN
  1036.  
  1037.       IF xresult >= 0.0 THEN
  1038.         magnitude_of_xresult:=xresult
  1039.       ELSE
  1040.         magnitude_of_xresult:=-xresult;
  1041.       IF magnitude_of_xresult >= 5.0E-3 THEN
  1042.         BEGIN
  1043.           digits_in_integer_part:=0;
  1044.           WHILE ((digits_in_integer_part <= 8)
  1045.           AND    (magnitude_of_xresult >= 1.0)) DO
  1046.             BEGIN
  1047.               magnitude_of_xresult:=magnitude_of_xresult/10.0;
  1048.               digits_in_integer_part:=digits_in_integer_part+1
  1049.             END;
  1050. (*
  1051.           IF digits_in_integer_part > 8 THEN
  1052.             WRITELN(OUTPUT,xresult:13)
  1053.           ELSE
  1054.             WRITELN(OUTPUT,xresult:10:8-digits_in_integer_part)
  1055. *)
  1056.         END;
  1057. (*
  1058.       ELSE
  1059.         WRITELN(OUTPUT,xresult:13)
  1060. *)
  1061.     END;
  1062.  
  1063. { ------------------------------------------------------------------------ }
  1064.  
  1065.   PROCEDURE output_error(error_msg : string_255;
  1066.                          VAR expression : string_255;
  1067.                          VAR expression_index : INTEGER);
  1068.  
  1069.     { this routine used to write the expression, the position of
  1070.       the error, and an error message to the screen. it has been
  1071.       reworked to keep the position of the error only. if more
  1072.       information is required, add the code here. the original
  1073.       calling convention has been preserved.
  1074.     }
  1075.  
  1076.     BEGIN
  1077.  
  1078.       {trap the error here to see in Turbo Debugger}
  1079.  
  1080.       CalcError := expression_index;
  1081.  
  1082.     END;
  1083.  
  1084. { ------------------------------------------------------------------------ }
  1085.  
  1086. procedure RawCalculate(MyFormula:string;var MyResult:real;var MyError:byte);
  1087.  
  1088. { this procedure will evaluate an expression without variables.
  1089.   it is called by the Calculate procedure once variable values
  1090.   have been inserted into the expression.
  1091.  
  1092.   MyError will be 0 for a successful evaluation.
  1093. }
  1094.  
  1095. begin
  1096.  
  1097.   expression := MyFormula;
  1098.   MyResult := 0;
  1099.   CalcError := 0;
  1100.   expression_length := length(MyFormula);
  1101.  
  1102.   { ---- Original code starts here ---- }
  1103.  
  1104.   error_detected:=FALSE;
  1105.   expression_index:=1;
  1106.   xresult:=simple_expression;
  1107.  
  1108.   IF error_detected THEN
  1109.     output_error(error_msg,expression,expression_index)
  1110.   ELSE
  1111.     BEGIN
  1112.       eat_leading_spaces;
  1113.       IF expression_index <= expression_length THEN
  1114.         output_error('Error:  expression followed by garbage',
  1115.                      expression,expression_index)
  1116.       ELSE
  1117.         output_value(xresult);
  1118.     END;
  1119.  
  1120.   { ---- Original code ends here ---- }
  1121.  
  1122.   MyResult := xresult;
  1123.   MyError := CalcError;
  1124.  
  1125. end; {RawCalc}
  1126.  
  1127. { ------------------------------------------------------------------------ }
  1128.  
  1129. procedure GetPointerTo(VariableID:str20;var MPtr:VariablePtr);
  1130.  
  1131. var
  1132.  
  1133.   Done : boolean;
  1134.   XPtr : VariablePtr;
  1135.  
  1136. begin
  1137.  
  1138.   MPtr := nil;
  1139.   XPtr := HPtr;
  1140.  
  1141.   Done := false;
  1142.   while (not Done) do begin
  1143.  
  1144.     if XPtr^.ID=VariableID then
  1145.       MPtr := XPtr;
  1146.  
  1147.     if XPtr^.Next=nil then
  1148.       Done := true
  1149.     else
  1150.       XPtr := XPtr^.Next;
  1151.  
  1152.   end; {while}
  1153.  
  1154. end; {GetPointerTo}
  1155.  
  1156. { ------------------------------------------------------------------------ }
  1157.  
  1158. procedure ReadVariable(VariableID:str20;var MyValue:real;var MyError:boolean);
  1159.  
  1160. var
  1161.  
  1162.   MPtr : VariablePtr;
  1163.  
  1164. begin
  1165.  
  1166.   MyError := false;
  1167.   MyValue := 0;
  1168.  
  1169.   GetPointerTo(VariableID,MPtr);
  1170.  
  1171.   if MPtr<>nil then begin
  1172.     MyValue := MPtr^.Value
  1173.   end
  1174.   else begin
  1175.     MyError := true;
  1176.   end;
  1177.  
  1178. end; {ReadVariable}
  1179.  
  1180. { ------------------------------------------------------------------------ }
  1181.  
  1182. procedure StoreVariable(VariableID:str20;MyValue:real);
  1183.  
  1184. var
  1185.  
  1186.   WorkingRec : VariableType;
  1187.  
  1188. begin
  1189.  
  1190.   fillchar(WorkingRec,sizeof(WorkingRec),0);
  1191.   WorkingRec.ID := VariableID;
  1192.   WorkingRec.Value := MyValue;
  1193.  
  1194.   If HPtr = nil then begin
  1195.  
  1196.     {this is the first record added to the list}
  1197.  
  1198.     New(HPtr);                                {allocate 1st record in LL }
  1199.     TPtr := HPtr;                             {init tail (= head)        }
  1200.     TPtr^ := WorkingRec;                      {add new record as head    }
  1201.     TPtr^.Next := nil;                        {set the next link for tail}
  1202.  
  1203.   end
  1204.   else begin
  1205.  
  1206.     GetPointerTo(VariableID,SPtr);
  1207.  
  1208.     if SPtr <> nil then begin
  1209.  
  1210.       {the list exists and so does the variable -- modify value}
  1211.  
  1212.       SPtr^.Value := MyValue;
  1213.  
  1214.     end
  1215.     else begin
  1216.  
  1217.       {the list exists, but the variable doesn't -- add it}
  1218.  
  1219.       New(SPtr);                          {allocate new record for LL }
  1220.       SPtr^ := WorkingRec;                {put info in new LL record  }
  1221.       TPtr^.Next := SPtr;                 {add new record as tail     }
  1222.       SPtr^.Next := nil;                  {set the new link for tail  }
  1223.       TPtr := SPtr;                       {point tail to new record   }
  1224.  
  1225.     end; {if-else}
  1226.  
  1227.   end;
  1228.  
  1229. end; {StoreVariable}
  1230.  
  1231. { ------------------------------------------------------------------------- }
  1232.  
  1233. Procedure DestroyFieldList(TempPtr:VariablePtr);
  1234.  
  1235. { This procedure recursively destroys a linked list }
  1236.  
  1237. Begin
  1238.  
  1239.   If TempPtr^.Next <> nil then
  1240.     DestroyFieldList(TempPtr^.Next);
  1241.  
  1242.   Dispose(TempPtr);
  1243.  
  1244. End;
  1245.  
  1246. { ------------------------------------------------------------------------ }
  1247.  
  1248. procedure DestroyList;
  1249.  
  1250. begin
  1251.  
  1252.   if HPtr <> Nil then
  1253.     DestroyFieldList(HPtr);
  1254.  
  1255.   HPtr := nil;
  1256.   TPtr := nil;
  1257.   SPtr := nil;
  1258.  
  1259. end; {DestroyList}
  1260.  
  1261. { ------------------------------------------------------------------------ }
  1262.  
  1263. procedure Calculate(MyFormula:string;var MyResult:real;var MyError:byte);
  1264.  
  1265. { this procedure will evaluate an expression containing variables.
  1266.   this routine will scan the expression for variables, removing
  1267.   the variable IDs and substituting the value into the expression.
  1268.   once all variable IDs have been removed, this procedure calls
  1269.   RawCalculate for expression evaluation.
  1270.  
  1271.   MyError will be 0 for a successful evaluation.
  1272. }
  1273.  
  1274. var
  1275.  
  1276.   VarStr,
  1277.   DestStr : string;
  1278.   Index   : byte;
  1279.   MyReal  : real;
  1280.   MyErr   : boolean;
  1281.  
  1282. begin
  1283.  
  1284.   {the first part of this routine is the preprocessor for variables.
  1285.    the formula string will be copied to another string. as the string
  1286.    is copied, values for any variables will be inserted where the
  1287.    variable ID was in the original string.}
  1288.  
  1289.   MyError := 0;
  1290.   DestStr := '';
  1291.   Index := 1;
  1292.  
  1293.   while Index <= length(MyFormula) do begin
  1294.  
  1295.     if MyFormula[Index]='@' then begin
  1296.  
  1297.       VarStr := '@';
  1298.       inc(Index);
  1299.       while (MyFormula[Index]<>'@') AND (Index<=length(MyFormula)) do begin
  1300.         VarStr := VarStr + MyFormula[Index];
  1301.         inc(Index);
  1302.       end; {while}
  1303.       VarStr := VarStr + '@';
  1304.  
  1305.       if VarStr[length(VarStr)]='@' then begin
  1306.         {read variable}
  1307.         ReadVariable(VarStr,MyReal,MyErr);
  1308.         if not MyErr then begin
  1309.           {substitute value for variable}
  1310.           str(MyReal,VarStr);
  1311.           DestStr := DestStr + VarStr;
  1312.         end
  1313.         else
  1314.           {didn't find variable}
  1315.           MyError := Index - length(VarStr);
  1316.       end
  1317.       else begin
  1318.         {ran out of formula!}
  1319.         MyError := Index - length(VarStr);
  1320.       end; {if-else}
  1321.  
  1322.     end
  1323.     else
  1324.       DestStr := DestStr + MyFormula[Index];
  1325.  
  1326.     inc(Index);
  1327.  
  1328.   end; {while}
  1329.  
  1330.   if MyError=0 then begin
  1331.     MyFormula := DestStr;
  1332.     {call RawCalculate to evaluate expression}
  1333.     RawCalculate(MyFormula,MyResult,MyError);
  1334.   end;
  1335.  
  1336. end; {Calc}
  1337.  
  1338. { ------------------------------------------------------------------------ }
  1339.  
  1340. procedure CalcAndStore(MyFormula:string;StoreID:str20;var MyError:byte);
  1341.  
  1342. { this routine will evaluate an expression containing variables
  1343.   and will store the xresult in the variable with the ID, StoreID.
  1344.   this routine calls Calculate to evaluate the expression.
  1345.  
  1346.   MyError will be 0 for a successful evaluation.
  1347. }
  1348.  
  1349. var
  1350.  
  1351.   MyResult : real;
  1352.  
  1353. begin
  1354.  
  1355.   {call Calculate to evaluate expression}
  1356.   Calculate(MyFormula,MyResult,MyError);
  1357.  
  1358.   if MyError=0 then
  1359.     StoreVariable(StoreID,MyResult);
  1360.  
  1361. end; {CalcAndStore}
  1362.  
  1363. { ------------------------------------------------------------------------ }
  1364.  
  1365. (* This is the original main program block, now unused. --- DJF
  1366.  
  1367. BEGIN
  1368.     REPEAT
  1369.       WRITELN(OUTPUT,' ');
  1370.       WRITE(OUTPUT,'Expression (RETURN to exit)?  ');
  1371.       READLN(INPUT,expression);
  1372.       expression_length:=LENGTH(expression);
  1373.       IF expression_length > 0 THEN
  1374.         BEGIN
  1375.           error_detected:=FALSE;
  1376.           expression_index:=1;
  1377.           xresult:=simple_expression;
  1378.           IF error_detected THEN
  1379.             output_error(error_msg,expression,expression_index)
  1380.           ELSE
  1381.             BEGIN
  1382.               eat_leading_spaces;
  1383.               IF expression_index <= expression_length THEN
  1384.                 output_error(
  1385.                  'Error:  expression followed by garbage',
  1386.                  expression,expression_index)
  1387.               ELSE
  1388.                 output_value(xresult)
  1389.             END
  1390.         END
  1391.     UNTIL (expression_length = 0)
  1392.   END.
  1393.  
  1394.   *)
  1395.  
  1396. { ------------------------------------------------------------------------ }
  1397.  
  1398. Begin  {init code}
  1399.  
  1400.   {set up linked list to empty state}
  1401.  
  1402.   HPtr := nil;
  1403.   TPtr := nil;
  1404.   SPtr := nil;
  1405.  
  1406.   CalcError := 0;
  1407.  
  1408. End.   {init code}
  1409.  
  1410.